﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using BesAsm.Emgaats.Core;
using BesAsm.Framework.MsAccessUtilities;
using BesAsm.Framework.Reporting;

namespace BesAsm.Emgaats.ModelBuilder
{
    /// <summary>
    /// Provides methods to write model hydraulics files
    /// </summary>
  public class HydraulicsBuilder
  {
    private Model _model;
    private string _dbPath;
    private const string MODEL_DEPLOY_HYDRAULICS_ACCESS_DB = "ModelDeployHydraulics.mdb";
    private AccessHelper _accessHelper;

    /// <summary>
    /// Initializes a new instance of the <see cref="HydraulicsBuilder"/> class.
    /// </summary>
    /// <param name="model">The model to deploy. The state of this model must be 
    /// at least ModelState.Built, or a ModelStateException will be thrown.</param>
    public HydraulicsBuilder(Model model)
    {      
      if (model.State < ModelState.Assembled)
        throw new ModelStateException(model.State, ModelState.Assembled, "Unable to create hydraulics builder: Model not yet built.");

      _model = model;
      _dbPath = Path.Combine(model.GetPathIfSet(ModelPathComponent.RootFolder), MODEL_DEPLOY_HYDRAULICS_ACCESS_DB);

      WriteHydraulicsDatabase();
    }

    private void WriteHydraulicsDatabase()
    {
      Messenger.ReportMessage("Copying bare ModelDeployHydraulics", ReportableMessageType.Info);
      FileStream outStream = null;
      try
      {
        outStream = new FileStream(_dbPath, FileMode.Create);
        byte[] data = Properties.Resources.ModelDeployHydraulics;
        outStream.Write(data, 0, data.Length);
        outStream.Flush();
      }
      finally
      {
        if (outStream != null)
          outStream.Close();
      }
    }

    /// <summary>
    /// Deploys the model hydraulic file
    /// </summary>
    /// <param name="hydraulicsFile">The hydraulics file to deploy.</param>
    public void DeployHydraulics()
    {
      string modelPath = _model.GetPathIfSet(ModelPathComponent.Pgdb);
      _accessHelper = null;
      try
      {
        _accessHelper = new AccessHelper(_dbPath);

        LinkModelTables(modelPath);
        CopyDataFromLinkedTables(modelPath);
        
        ExecuteLinkQueries();        

        ExportXPX();
      }
      finally
      {
        if (_accessHelper != null)
          _accessHelper.Dispose();
      }

      //Relink tables
      //Execute action query table

    }

    private void LinkModelTables(string modelPath)
    {
      Messenger.ReportMessage("Linking tables", ReportableMessageType.Info);
      _accessHelper.LinkTable("MODEL_DSCS", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_LINKS", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_NODES", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_SPECIAL_LINKS_DATA", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_SPECIAL_LINKS", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_CROSS_SECTIONS_DATA", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_CROSS_SECTIONS", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_PIPE_SHAPES", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_PIPE_SHAPES_DATA", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_PUMP_CURVES", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_SAN_PATTERNS", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_IC_DISCOS", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_IC_DRYWELLS", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_IC_NODE_REDIRECTORS", modelPath, ExternalDatabaseType.MsAccess);
      
      _accessHelper.LinkTable("MODEL_DSCS_CALCULATED", modelPath, ExternalDatabaseType.MsAccess);
      _accessHelper.LinkTable("MODEL_SSCS_CALCULATED", modelPath, ExternalDatabaseType.MsAccess);
    }

    private void CopyDataFromLinkedTables(string modelPath)
    {
      Messenger.ReportMessage("Copying data into tables", ReportableMessageType.Info);
      _accessHelper.CopyTable("MODEL_DSCS", "EMG3_DSCS");
      _accessHelper.CopyTable("MODEL_LINKS", "EMG3_LINKS");
      _accessHelper.CopyTable("MODEL_NODES", "EMG3_NODES");
      _accessHelper.CopyTable("MODEL_SPECIAL_LINKS_DATA", "EMG3_SPECIAL_LINKS_DATA");
      _accessHelper.CopyTable("MODEL_SPECIAL_LINKS", "EMG3_SPECIAL_LINKS");
      _accessHelper.CopyTable("MODEL_CROSS_SECTIONS_DATA", "EMG3_CROSS_SECTIONS_DATA");
      _accessHelper.CopyTable("MODEL_CROSS_SECTIONS", "EMG3_CROSS_SECTIONS");
      _accessHelper.CopyTable("MODEL_PIPE_SHAPES", "EMG3_PIPE_SHAPES");
      _accessHelper.CopyTable("MODEL_PIPE_SHAPES_DATA", "EMG3_PIPE_SHAPES_DATA");
      _accessHelper.CopyTable("MODEL_PUMP_CURVES", "EMG3_PUMP_CURVES");
      _accessHelper.CopyTable("MODEL_SAN_PATTERNS", "EMG3_SAN_PATTERNS");
      _accessHelper.CopyTable("MODEL_IC_DISCOS", "EMG3_IC_DISCOS");
      _accessHelper.CopyTable("MODEL_IC_DRYWELLS", "EMG3_IC_DRYWELLS");
      _accessHelper.CopyTable("MODEL_IC_NODE_REDIRECTORS", "EMG3_IC_NODE_REDIRECTORS");

      _accessHelper.CopyTable("MODEL_DSCS_CALCULATED", "EMG3_DSCS_CALCULATED");
      _accessHelper.CopyTable("MODEL_SSCS_CALCULATED", "EMG3_SSCS_CALCULATED");

      _accessHelper.AddField("EMG3_DSCS", "ParcelID_deprecated", FieldType.Long, true);
      _accessHelper.AddField("EMG3_DSCS", "DivideID_deprecated", FieldType.Long, true);
      _accessHelper.ExecuteActionQuery("EMG3_update_deprecated_dsc_ids");    
    }   

    private void ExecuteLinkQueries()
    {
      Messenger.ReportMessage("Running special and parallel links macros", ReportableMessageType.Info);
      _accessHelper.ExecuteMacro("XP_SPECIAL_LINKS");
      _accessHelper.ExecuteMacro("XP_PARALLEL_LINKS");
    }

    private void ExportXPX()
    {
      string hydraulicsFile =
        Path.Combine(_model.GetPathIfSet(ModelPathComponent.RootFolder), "XPExtran.XPX");
      Messenger.ReportMessage("Exporting XPX to " + hydraulicsFile, ReportableMessageType.Info);

      _accessHelper.UpdateField("TimeFrame", "[value]",
        _model.TimeFrame.ToUpper() == "EXISTING" ? "EX" : "FU");

      _accessHelper.ExportQueryTable("EMG3_04_ExportXPX", "QueryName", "dumpOrder", hydraulicsFile,
        FileType.Raw);
    }

  }
}
